using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace Limestone.Storage.XML
{
    internal class FileHelpers:IFileHelpers
    {
        private readonly IXmlStorageConfig _xmlStorageConfig;

        public FileHelpers(IXmlStorageConfig xmlStorageConfig)
        {
            _xmlStorageConfig = xmlStorageConfig;
        }

        public string ToDiscPath(string path)
        {
            path = path.Replace('/', '\\');
            return Path.Combine(_xmlStorageConfig.BasePagePath, (path.First() == '\\') ? path.Substring(1) : path);
        }
        public string GetPageFilePath(string pagePath)
        {
            var path = ToDiscPath(pagePath);
            path += Directory.Exists(path) ? "\\" + _xmlStorageConfig.FolderIndexPageName + ".page" : ".page";
            return path;
        }

        public PageDiscInfo GetPageDiscInfo(string pagePath)
        {
            var path = ToDiscPath(pagePath);
            var isDir = Directory.Exists(path);
            var parentDirectoryPath = path.Substring(0, path.LastIndexOf("\\", StringComparison.Ordinal));

            return new PageDiscInfo
                       {
                           IsDirectory = isDir,
                           PageFilePath = path + ((isDir) ? "\\" + _xmlStorageConfig.FolderIndexPageName + ".page" : ".page"),
                           ResidesInDirectory = isDir ? path + "\\" : parentDirectoryPath
                       };
        }

        public string ToValidName(string name)
        {
            var builder = new StringBuilder();
            var invalid = Path.GetInvalidFileNameChars();
            foreach (var cur in name.Where(cur => !invalid.Contains(cur)))
            {
                builder.Append(cur);
            }
            return builder.ToString();
        }

        public T SaveToFile<T>(T templateOrPage, string path)
        {
            TextWriter w = null;

            var previousVersionContent = (File.Exists(path)) ? File.ReadAllText(path) : "";

            try
            {
                var s = new XmlSerializer(typeof(T));
                w = new StreamWriter(path);
                s.Serialize(w, templateOrPage);
            }
            catch (Exception)
            {
                // Rollback
                if (!String.IsNullOrEmpty(previousVersionContent))
                {
                    File.WriteAllText(path, previousVersionContent);
                }
                return default(T);
            }
            finally
            {
                if (w != null)
                    w.Close();
            }

            return templateOrPage;
        }


        public void EnsureParentDirectoryExists(string folderPath)
        {
            if (folderPath == "" || Directory.Exists(folderPath))
                return;

            // check closest parent
            var parentFolderPath = Path.GetDirectoryName(folderPath);
            if (!Directory.Exists(parentFolderPath))
                EnsureParentDirectoryExists(parentFolderPath);

            // create the folder
            Directory.CreateDirectory(folderPath);


            // check if there is a page which should be moved and turned into an index.page
            var indexPath = Path.Combine(_xmlStorageConfig.BasePagePath, folderPath + ".page");
            if (File.Exists(indexPath))
            {
                File.Move(indexPath, Path.Combine(folderPath, _xmlStorageConfig.FolderIndexPageName + ".page"));
            }

            /* not doing this. It creates a loop since saving the page will check for existence of the very same file
            // add an index page to the folder
            string folderIndexFilePath = folderPath + "/" + Config.FolderIndexPageName + ".page";
            if (!File.Exists(HttpContext.Current.Server.MapPath(folderIndexFilePath)))
            {
                Page indexPage = new Page("Index", true);
                indexPage.Site = currentSite;
                indexPage.TemplatePath = Config.DefaultIndexTemplatePath;
                indexPage.Path = folderIndexFilePath;
                indexPage.Save();
            }
             * */
        }

        public T LoadObjectFromDisc<T>(string path)
        {
            TextReader r = null;
            T newObject;
            try
            {
                var s = new XmlSerializer(typeof(T));
                r = new StreamReader(path);
                newObject = (T)s.Deserialize(r);
            }
            catch (Exception)
            {
                return default(T);
            }
            finally
            {
                if (r != null)
                    r.Close();
            }
            return newObject;
        }
    }
}